#pragma once
#include<iostream>
#include<vector>
#include<pthread.h>
#include<unistd.h>

#include<semaphore.h>



#define defaults 10


template<class T>
class BlockQueue
{
public:
    BlockQueue(int num = defaults)
        :head(0)
        , tail(0)
        , q_(defaults)
        , cap_(defaults)
    {
        pthread_mutex_init(&clock_, nullptr);
        pthread_mutex_init(&plock_, nullptr);
        sem_init(&Spacedata_, 0, num);
        sem_init(&data_, 0, 0);

    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&clock_);
        pthread_mutex_destroy(&plock_);
        sem_destroy(&Spacedata_);
        sem_destroy(&data_);
    }

    void P(sem_t* sem)
    {
        sem_wait(sem);
    }

    void V(sem_t* sem)
    {
        sem_post(sem);
    }

    void push(T& x)
    {
        P(&Spacedata_);
        pthread_mutex_lock(&plock_);
        q_[tail++] = x;
        tail %= cap_;
        V(&data_);
        pthread_mutex_unlock(&plock_);
    }

    T pop()
    {
        P(&data_);
        pthread_mutex_lock(&clock_);
        T t = q_[head++];
        head %= cap_;
        V(&Spacedata_);
        pthread_mutex_unlock(&clock_);
        return t;
    }

private:
    std::vector<T>q_;
    int cap_;
    int head;
    int tail;
    std::vector<int>a;


    pthread_mutex_t clock_;
    pthread_mutex_t plock_;

    sem_t Spacedata_;
    sem_t data_;

};
